package cluster

import "sync"

const (
	CLUSTER_FULL_PREFIX = "/server/%d/%d" // /server/<server_type>/<serverid>
)

var DEFAULT ICluster
var once sync.Once

type RegisterCenter int

const (
	ETCD RegisterCenter = iota
)

type IDiscovery interface {
	Init()
	Register(node INode) error
	Discovery(svrs ...int32) ([]INode, error)
	UnRegister(node INode) error
}

type ICluster interface {
	Init(regType RegisterCenter, node INode)
	ObserveNodeType(nodeType ...int32)
	GetNodes(nodeType int32) []INode
}

type Cluster struct {
	discovery    IDiscovery
	observeNodes map[int32]map[int32]INode //当前观察到的节点
}

func (c *Cluster) Init(regType RegisterCenter, node INode) {
	switch regType {
	case ETCD:
		discovery := &etcdDiscovery{
			dwatch: func(nodeType int32, nodeId int32) {
				nodes := c.observeNodes[nodeType]
				if nodes != nil {
					delete(nodes, nodeId)
				}
			},
			pwatch: func(node INode) {
				if _, ok := c.observeNodes[node.NodeType()]; !ok {
					c.observeNodes[node.NodeType()] = make(map[int32]INode)
				}
				c.observeNodes[node.NodeType()][node.NodeId()] = node
			},
		}
		c.discovery = discovery
	}
	c.discovery.Init()
	c.discovery.Register(node)
}

func (c *Cluster) ObserveNodeType(nodeType ...int32) {
	nodes, err := c.discovery.Discovery(nodeType...)
	if err != nil {
		panic(err)
	}
	for _, node := range nodes {
		if _, ok := c.observeNodes[node.NodeType()]; !ok {
			c.observeNodes[node.NodeType()] = make(map[int32]INode)
		}
		c.observeNodes[node.NodeType()][node.NodeId()] = node
	}
}

func (c *Cluster) GetNodes(nodeType int32) []INode {
	nodes := c.observeNodes[nodeType]
	if nodes == nil {
		return nil
	}
	var result []INode
	for _, node := range nodes {
		result = append(result, node)
	}
	return result
}

func Setup() {
	once.Do(func() {
		DEFAULT = &Cluster{
			observeNodes: make(map[int32]map[int32]INode),
		}
	})
}
